home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Dev / gcc263-src.lha / gcc-2.6.3 / config / tahoe / tahoe.c < prev    next >
C/C++ Source or Header  |  1992-07-27  |  14KB  |  565 lines

  1. /* Subroutines for insn-output.c for Tahoe.
  2.    Copyright (C) 1989, 1991 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU CC.
  5.  
  6. GNU CC is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. GNU CC is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU CC; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20.  
  21. #include "config.h"
  22. #include "rtl.h"
  23. #include "regs.h"
  24. #include "hard-reg-set.h"
  25. #include "real.h"
  26. #include "insn-config.h"
  27. #include "conditions.h"
  28. #include "insn-flags.h"
  29. #include "output.h"
  30. #include "insn-attr.h"
  31.  
  32. /*
  33.  * File: output-tahoe.c
  34.  *
  35.  * Original port made at the University of Buffalo by Devon Bowen,
  36.  * Dale Wiles and Kevin Zachmann.
  37.  *
  38.  * Changes for HCX by Piet van Oostrum,
  39.  * University of Utrecht, The Netherlands (piet@cs.ruu.nl)
  40.  *
  41.  * Speed tweaks by Michael Tiemann (tiemann@lurch.stanford.edu).
  42.  *
  43.  * Mail bugs reports or fixes to:    gcc@cs.buffalo.edu
  44.  */
  45.  
  46.  
  47. /* On tahoe, you have to go to memory to convert a register
  48.    from sub-word to word.  */
  49.  
  50. rtx tahoe_reg_conversion_loc;
  51.  
  52. int
  53. extendable_operand (op, mode)
  54.      rtx op;
  55.      enum machine_mode mode;
  56. {
  57.   if ((GET_CODE (op) == REG
  58.        || (GET_CODE (op) == SUBREG
  59.        && GET_CODE (SUBREG_REG (op)) == REG))
  60.       && tahoe_reg_conversion_loc == 0)
  61.     tahoe_reg_conversion_loc = assign_stack_local (SImode, GET_MODE_SIZE (SImode));
  62.   return general_operand (op, mode);
  63. }
  64.  
  65. /* most of the print_operand_address function was taken from the vax    */
  66. /* since the modes are basically the same. I had to add a special case,    */
  67. /* though, for symbol references with offsets.                */
  68.  
  69. #include <stdio.h>
  70.  
  71. print_operand_address (file, addr)
  72.      FILE *file;
  73.      register rtx addr;
  74. {
  75.   register rtx reg1, reg2, breg, ireg;
  76.   rtx offset;
  77.   static char *reg_name[] = REGISTER_NAMES;
  78.  
  79.  retry:
  80.   switch (GET_CODE (addr))
  81.     {
  82.     case MEM:
  83.       fprintf (file, "*");
  84.       addr = XEXP (addr, 0);
  85.       goto retry;
  86.  
  87.     case REG:
  88.       fprintf (file, "(%s)", reg_name [REGNO (addr)]);
  89.       break;
  90.  
  91.     case PRE_DEC:
  92.       fprintf (file, "-(%s)", reg_name [REGNO (XEXP (addr, 0))]);
  93.       break;
  94.  
  95.     case POST_INC:
  96.       fprintf (file, "(%s)+", reg_name [REGNO (XEXP (addr, 0))]);
  97.       break;
  98.  
  99.     case PLUS:
  100.       reg1 = 0;    reg2 = 0;
  101.       ireg = 0;    breg = 0;
  102.       offset = 0;
  103.  
  104.       if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
  105.       && GET_CODE (XEXP (addr, 1)) == CONST_INT)
  106.     output_addr_const (file, addr);
  107.  
  108.       if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
  109.       && GET_CODE (XEXP (addr, 0)) == CONST_INT)
  110.     output_addr_const (file, addr);
  111.  
  112.       if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
  113.       || GET_CODE (XEXP (addr, 0)) == MEM)
  114.     {
  115.       offset = XEXP (addr, 0);
  116.       addr = XEXP (addr, 1);
  117.     }
  118.       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
  119.            || GET_CODE (XEXP (addr, 1)) == MEM)
  120.     {
  121.       offset = XEXP (addr, 1);
  122.       addr = XEXP (addr, 0);
  123.     }
  124.       if (GET_CODE (addr) != PLUS)
  125.     ;
  126.       else if (GET_CODE (XEXP (addr, 0)) == MULT)
  127.     {
  128.       reg1 = XEXP (addr, 0);
  129.       addr = XEXP (addr, 1);
  130.     }
  131.       else if (GET_CODE (XEXP (addr, 1)) == MULT)
  132.     {
  133.       reg1 = XEXP (addr, 1);
  134.       addr = XEXP (addr, 0);
  135.     }
  136.       else if (GET_CODE (XEXP (addr, 0)) == REG)
  137.     {
  138.       reg1 = XEXP (addr, 0);
  139.       addr = XEXP (addr, 1);
  140.     }
  141.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  142.     {
  143.       reg1 = XEXP (addr, 1);
  144.       addr = XEXP (addr, 0);
  145.     }
  146.       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
  147.     {
  148.       if (reg1 == 0)
  149.         reg1 = addr;
  150.       else
  151.         reg2 = addr;
  152.       addr = 0;
  153.     }
  154.       if (offset != 0)
  155.     {
  156.       if (addr != 0) abort ();
  157.       addr = offset;
  158.     }
  159.       if (reg1 != 0 && GET_CODE (reg1) == MULT)
  160.     {
  161.       breg = reg2;
  162.       ireg = reg1;
  163.     }
  164.       else if (reg2 != 0 && GET_CODE (reg2) == MULT)
  165.     {
  166.       breg = reg1;
  167.       ireg = reg2;
  168.     }
  169.       else if (reg2 != 0 || GET_CODE (addr) == MEM)
  170.     {
  171.       breg = reg2;
  172.       ireg = reg1;
  173.     }
  174.       else
  175.     {
  176.       breg = reg1;
  177.       ireg = reg2;
  178.     }
  179.       if (addr != 0)
  180.     output_address (offset);
  181.       if (breg != 0)
  182.     {
  183.       if (GET_CODE (breg) != REG)
  184.         abort ();
  185.       fprintf (file, "(%s)", reg_name[REGNO (breg)]);
  186.     }
  187.       if (ireg != 0)
  188.     {
  189.       if (GET_CODE (ireg) == MULT)
  190.         ireg = XEXP (ireg, 0);
  191.       if (GET_CODE (ireg) != REG)
  192.         abort ();
  193.       fprintf (file, "[%s]", reg_name[REGNO (ireg)]);
  194.     }
  195.       break;
  196.  
  197.     default:
  198.       output_addr_const (file, addr);
  199.     }
  200. }
  201.  
  202. /* Do a quick check and find out what the best way to do the */
  203. /* mini-move is. Could be a push or a move.....             */
  204.  
  205. static char *
  206. singlemove_string (operands)
  207.      rtx *operands;
  208. {
  209.   if (operands[1] == const0_rtx)
  210.       return "clrl %0";
  211.   if (push_operand (operands[0], SImode))
  212.     return "pushl %1";
  213.   return "movl %1,%0";
  214. }
  215.  
  216. /* given the rtx for an address, return true if the given */
  217. /* register number is used in the address somewhere.      */
  218.  
  219. regisused(addr,regnum)
  220. rtx addr;
  221. int regnum;
  222. {
  223.     if (GET_CODE(addr) == REG)
  224.         if (REGNO(addr) == regnum)
  225.             return (1);
  226.         else
  227.             return (0);
  228.  
  229.     if (GET_CODE(addr) == MEM)
  230.         return regisused(XEXP(addr,0),regnum);
  231.  
  232.     if ((GET_CODE(addr) == MULT) || (GET_CODE(addr) == PLUS))
  233.         return ((regisused(XEXP(addr,0),regnum)) ||
  234.                     (regisused(XEXP(addr,1),regnum)));
  235.  
  236.     return 0;
  237. }
  238.  
  239.  
  240. /* Given some rtx, traverse it and return the register used in a */
  241. /* index. If no index is found, return 0.             */
  242.  
  243. rtx
  244. index_reg(addr)
  245. rtx addr;
  246. {
  247.     rtx temp;
  248.  
  249.     if (GET_CODE(addr) == MEM)
  250.         return index_reg(XEXP(addr,0));
  251.  
  252.     if (GET_CODE(addr) == MULT)
  253.         if (GET_CODE(XEXP(addr,0)) == REG)
  254.             return XEXP(addr,0);
  255.         else
  256.             return XEXP(addr,1);
  257.  
  258.     if (GET_CODE(addr) == PLUS)
  259.         if (temp = index_reg(XEXP(addr,0)))
  260.             return temp;
  261.         else
  262.             return index_reg(XEXP(addr,1));
  263.  
  264.     return 0;
  265. }
  266.  
  267.  
  268. /* simulate the move double by generating two movl's. You have */
  269. /* to be careful about mixing modes here.               */
  270.  
  271. char *
  272. output_move_double (operands)
  273.      rtx *operands;
  274. {
  275.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, INDOP, CNSTOP, RNDOP }
  276.     optype0, optype1;
  277.   rtx latehalf[2];
  278.   rtx shftreg0 = 0, shftreg1 = 0;
  279.   rtx temp0 = 0, temp1 = 0;
  280.   rtx addreg0 = 0, addreg1 = 0;
  281.   int dohighfirst = 0;
  282.  
  283.   /* First classify both operands. */
  284.  
  285.   if (REG_P (operands[0]))
  286.     optype0 = REGOP;
  287.   else if ((GET_CODE(operands[0])==MEM) && (shftreg0=index_reg(operands[0])))
  288.     optype0 = INDOP;
  289.   else if (offsettable_memref_p (operands[0]))
  290.     optype0 = OFFSOP;
  291.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) {
  292.     optype0 = PUSHOP;
  293.     dohighfirst++;
  294.   } else if (GET_CODE (operands[0]) == MEM)
  295.     optype0 = MEMOP;
  296.   else
  297.     optype0 = RNDOP;
  298.  
  299.   if (REG_P (operands[1]))
  300.     optype1 = REGOP;
  301.   else if ((GET_CODE(operands[1])==MEM) && (shftreg1=index_reg(operands[1])))
  302.     optype1 = INDOP;
  303.   else if (offsettable_memref_p (operands[1]))
  304.     optype1 = OFFSOP;
  305.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  306.     optype1 = POPOP; 
  307.   else if (GET_CODE (operands[1]) == MEM)
  308.     optype1 = MEMOP;
  309.   else if (CONSTANT_P (operands[1]))
  310.     optype1 = CNSTOP;
  311.   else
  312.     optype1 = RNDOP;
  313.  
  314.   /* set up for the high byte move for operand zero */
  315.  
  316.   switch (optype0) {
  317.  
  318.     /* if it's a register, just use the next highest in the */
  319.     /* high address move.                    */
  320.  
  321.     case REGOP  : latehalf[0] = gen_rtx (REG,SImode,REGNO(operands[0])+1);
  322.               break;
  323.  
  324.     /* for an offsettable address, use the gcc function to  */
  325.     /* modify the operand to get an offset of 4 higher for  */
  326.     /* the second move.                    */
  327.  
  328.     case OFFSOP : latehalf[0] = adj_offsettable_operand (operands[0], 4);
  329.               break;
  330.  
  331.     /* if the operand is MEMOP type, it must be a pointer    */
  332.     /* to a pointer. So just remember to increase the mem    */
  333.     /* location and use the same operand.            */
  334.  
  335.     case MEMOP  : latehalf[0] = operands[0];
  336.               addreg0 = XEXP(operands[0],0);
  337.               break;
  338.  
  339.     /* if we're dealing with a push instruction, just leave */
  340.     /* the operand alone since it auto-increments.        */
  341.  
  342.     case PUSHOP : latehalf[0] = operands[0];
  343.               break;
  344.  
  345.     /* YUCK! Indexed addressing!! If the address is considered   */
  346.     /* offsettable, go use the offset in the high part. Otherwise */
  347.     /* find what exactly is being added to the multiplication. If */
  348.     /* it's a mem reference, increment that with the high part   */
  349.     /* being unchanged to cause the shift. If it's a reg, do the */
  350.     /* same. If you can't identify it, abort. Remember that the  */
  351.     /* shift register was already set during identification.     */
  352.  
  353.     case INDOP  : if (offsettable_memref_p(operands[0])) {
  354.                latehalf[0] = adj_offsettable_operand(operands[0],4);
  355.                break;
  356.               }
  357.  
  358.               latehalf[0] = operands[0];
  359.  
  360.               temp0 = XEXP(XEXP(operands[0],0),0);
  361.                       if (GET_CODE(temp0) == MULT) {
  362.                temp1 = temp0;
  363.                temp0 = XEXP(XEXP(operands[0],0),1);
  364.               } else {
  365.                temp1 = XEXP(XEXP(operands[0],0),1);
  366.                if (GET_CODE(temp1) != MULT)
  367.                 abort();
  368.               }
  369.  
  370.               if (GET_CODE(temp0) == MEM)
  371.                addreg0 = temp0;
  372.               else if (GET_CODE(temp0) == REG)
  373.                addreg0 = temp0;
  374.               else
  375.                abort();
  376.  
  377.               break;
  378.  
  379.     /* if we don't know the operand type, print a friendly  */
  380.     /* little error message...   8-)            */
  381.  
  382.     case RNDOP  :
  383.     default     : abort();
  384.   }
  385.  
  386.   /* do the same setup for operand one */
  387.  
  388.   switch (optype1) {
  389.  
  390.     case REGOP  : latehalf[1] = gen_rtx(REG,SImode,REGNO(operands[1])+1);
  391.               break;
  392.  
  393.     case OFFSOP : latehalf[1] = adj_offsettable_operand (operands[1], 4);
  394.               break;
  395.  
  396.     case MEMOP  : latehalf[1] = operands[1];
  397.               addreg1 = XEXP(operands[1],0);
  398.               break;
  399.  
  400.     case POPOP  : latehalf[1] = operands[1];
  401.               break;
  402.  
  403.     case INDOP  : if (offsettable_memref_p(operands[1])) {
  404.                latehalf[1] = adj_offsettable_operand(operands[1],4);
  405.                break;
  406.               }
  407.  
  408.               latehalf[1] = operands[1];
  409.  
  410.               temp0 = XEXP(XEXP(operands[1],0),0);
  411.                       if (GET_CODE(temp0) == MULT) {
  412.                temp1 = temp0;
  413.                temp0 = XEXP(XEXP(operands[1],0),1);
  414.               } else {
  415.                temp1 = XEXP(XEXP(operands[1],0),1);
  416.                if (GET_CODE(temp1) != MULT)
  417.                 abort();
  418.               }
  419.  
  420.               if (GET_CODE(temp0) == MEM)
  421.                addreg1 = temp0;
  422.               else if (GET_CODE(temp0) == REG)
  423.                addreg1 = temp0;
  424.               else
  425.                abort();
  426.  
  427.               break;
  428.  
  429.     case CNSTOP :
  430.       if (GET_CODE (operands[1]) == CONST_DOUBLE)
  431.         split_double (operands[1], &operands[1], &latehalf[1]);
  432.       else if (CONSTANT_P (operands[1]))
  433.         latehalf[1] = const0_rtx;
  434.       else abort ();
  435.       break;
  436.  
  437.     case RNDOP  :
  438.     default     : abort();
  439.   }
  440.  
  441.  
  442.   /* double the register used for shifting in both of the operands */
  443.   /* but make sure the same register isn't doubled twice!       */
  444.  
  445.   if (shftreg0 && shftreg1 && (rtx_equal_p(shftreg0,shftreg1)))
  446.     output_asm_insn("addl2 %0,%0", &shftreg0);
  447.   else {
  448.     if (shftreg0)
  449.         output_asm_insn("addl2 %0,%0", &shftreg0);
  450.     if (shftreg1)
  451.         output_asm_insn("addl2 %0,%0", &shftreg1);
  452.   }
  453.  
  454.   /* if the destination is a register and that register is needed in  */
  455.   /* the source addressing mode, swap the order of the moves since we */
  456.   /* don't want this destroyed til last. If both regs are used, not   */
  457.   /* much we can do, so abort. If these becomes a problem, maybe we   */
  458.   /* can do it on the stack?                          */
  459.  
  460.   if (GET_CODE(operands[0])==REG && regisused(operands[1],REGNO(operands[0])))
  461.     if (regisused(latehalf[1],REGNO(latehalf[0])))
  462.         8;
  463.     else
  464.         dohighfirst++;
  465.  
  466.   /* if we're pushing, do the high address part first. */
  467.  
  468.   if (dohighfirst) {
  469.  
  470.     if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
  471.         output_asm_insn("addl2 $4,%0", &addreg0);
  472.     else {
  473.         if (addreg0)
  474.             output_asm_insn("addl2 $4,%0", &addreg0);
  475.         if (addreg1)
  476.             output_asm_insn("addl2 $4,%0", &addreg1);
  477.     }
  478.  
  479.     output_asm_insn(singlemove_string(latehalf), latehalf);
  480.  
  481.     if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
  482.         output_asm_insn("subl2 $4,%0", &addreg0);
  483.     else {
  484.         if (addreg0)
  485.             output_asm_insn("subl2 $4,%0", &addreg0);
  486.         if (addreg1)
  487.             output_asm_insn("subl2 $4,%0", &addreg1);
  488.     }
  489.  
  490.     return singlemove_string(operands);
  491.   }
  492.  
  493.   output_asm_insn(singlemove_string(operands), operands);
  494.  
  495.   if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
  496.     output_asm_insn("addl2 $4,%0", &addreg0);
  497.   else {
  498.     if (addreg0)
  499.         output_asm_insn("addl2 $4,%0", &addreg0);
  500.     if (addreg1)
  501.         output_asm_insn("addl2 $4,%0", &addreg1);
  502.   }
  503.  
  504.   output_asm_insn(singlemove_string(latehalf), latehalf);
  505.  
  506.   if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
  507.     output_asm_insn("subl2 $4,%0", &addreg0);
  508.   else {
  509.     if (addreg0)
  510.         output_asm_insn("subl2 $4,%0", &addreg0);
  511.     if (addreg1)
  512.         output_asm_insn("subl2 $4,%0", &addreg1);
  513.   }
  514.  
  515.   if (shftreg0 && shftreg1 && (rtx_equal_p(shftreg0,shftreg1)))
  516.     output_asm_insn("shar $1,%0,%0", &shftreg0);
  517.   else {
  518.     if (shftreg0)
  519.         output_asm_insn("shar $1,%0,%0", &shftreg0);
  520.     if (shftreg1)
  521.         output_asm_insn("shar $1,%0,%0", &shftreg1);
  522.   }
  523.  
  524.   return "";
  525. }
  526.  
  527.  
  528. /* This checks if a zero_extended cmp[bw] can be replaced by a sign_extended
  529.    cmp[bw]. This can be done if the operand is a constant that fits in a
  530.    byte/word or a memory operand. Besides that the next instruction must be an
  531.    unsigned compare. Some of these tests are done by the machine description */
  532.  
  533. int
  534. tahoe_cmp_check (insn, op, max)
  535. rtx insn, op; int max;
  536. {
  537.     if (GET_CODE (op) == CONST_INT
  538.     && ( INTVAL (op) < 0 || INTVAL (op) > max ))
  539.     return 0;
  540.     {
  541.     register rtx next = NEXT_INSN (insn);
  542.  
  543.     if ((GET_CODE (next) == JUMP_INSN
  544.        || GET_CODE (next) == INSN
  545.        || GET_CODE (next) == CALL_INSN))
  546.         {
  547.         next = PATTERN (next);
  548.         if (GET_CODE (next) == SET
  549.             && SET_DEST (next) == pc_rtx
  550.             && GET_CODE (SET_SRC (next)) == IF_THEN_ELSE)
  551.             switch (GET_CODE (XEXP (SET_SRC (next), 0)))
  552.             {
  553.             case EQ:
  554.             case NE:
  555.             case LTU:
  556.             case GTU:
  557.             case LEU:
  558.             case GEU:
  559.                 return 1;
  560.             }
  561.         }
  562.     }
  563.     return 0;
  564. }
  565.